/**
 * 计算两个地理位置之间的球面距离
 *
 * @param {number} lat1 - 第一个地理位置的纬度
 * @param {number} lng1 - 第一个地理位置的经度
 * @param {number} lat2 - 第二个地理位置的纬度
 * @param {number} lng2 - 第二个地理位置的经度
 * @returns {number} 返回两个地理位置之间的球面距离，单位为公里，保留四位小数
 */
export function getDistance(lat1, lng1, lat2, lng2) {
  // 将纬度转换为弧度
  var radLat1 = (lat1 * Math.PI) / 180.0;
  // 将第二个纬度转换为弧度
  var radLat2 = (lat2 * Math.PI) / 180.0;
  // 计算两个纬度之差转换为弧度
  var a = radLat1 - radLat2;
  // 将两个经度转换为弧度，并计算差值
  var b = (lng1 * Math.PI) / 180.0 - (lng2 * Math.PI) / 180.0;
  // 使用Haversine公式计算两点之间的球面距离
  var s =
    2 *
    Math.asin(
      Math.sqrt(
        Math.pow(Math.sin(a / 2), 2) +
          Math.cos(radLat1) * Math.cos(radLat2) * Math.pow(Math.sin(b / 2), 2)
      )
    );
  // 将球面距离转换为实际距离，使用地球半径（单位：公里）
  s = s * 6378.137; // EARTH_RADIUS;
  // 对计算结果进行四舍五入，保留四位小数
  s = Math.round(s * 10000) / 10000;
  return s;
}

/**
 *
 * @param {*} p1 原点坐标
 * @param {*} p2 参考点
 * @param {*} getDistance2 ctMap.GeometryUtil.distance
 * @param {*} isMapApi 调用的是华苏地图api getDistance2是通用库GeometryUtil
 */
export function getTwoPointAngle(p1, p2, getDistance2, isMapApi) {
  // 将p1和p2坐标分解为x和y坐标
  const [x1, y1] = p1;
  const [x2, y2] = p2;

  // 创建另外两个点b和d，用于计算与p1的距离
  const b = [x1, y2];
  const d = [x2, y1];

  let ab, ad;

  // 根据isMapApi的值判断调用的是哪种api来计算距离
  if (isMapApi) {
    // 如果是华苏地图api
    ab = getDistance2.distance({
      p1: b,
      p2: p1,
    });
    ad = getDistance2.distance({
      p1: d,
      p2: p1,
    });
  } else {
    // 如果是通用库GeometryUtil
    ab = getDistance2(b, p1);
    ad = getDistance2(d, p1);
  }

  let angle;

  // 根据ad和ab的值选择计算角度的方法
  if (ad === 0 || ab === 0) {
    // 如果ad或ab为0，则使用countAngle1方法计算角度
    angle = countAngle1(x1, x2, y1, y2);
  } else {
    // 否则使用countAngle2方法计算角度
    angle = countAngle2(x1, x2, y1, y2, ad, ab);
  }

  // 返回角度值，保留两位小数
  return angle.toFixed(2);
}

/**
 * 计算两个点之间的角度
 *
 * @param {number} x1 - 第一个点的x坐标
 * @param {number} x2 - 第二个点的x坐标
 * @param {number} y1 - 第一个点的y坐标
 * @param {number} y2 - 第二个点的y坐标
 * @returns {number} 返回两个点之间的角度，角度以度为单位，取值范围为0-360度
 */
function countAngle1(x1, x2, y1, y2) {
  let angle = 0;

  // 当x坐标相同且y2大于或等于y1时，角度为0度
  if (x2 === x1 && y2 >= y1) {
    angle = 0;
  }

  // 当x坐标相同且y2小于y1时，角度为180度
  if (x2 === x1 && y2 < y1) {
    angle = 180;
  }

  // 当y坐标相同且x2大于x1时，角度为90度
  if (x2 > x1 && y2 === y1) {
    angle = 90;
  }

  // 当y坐标相同且x2小于x1时，角度为270度
  if (x2 < x1 && y2 === y1) {
    angle = 270;
  }

  return angle;
}

/**
 * 计算两点之间的角度
 *
 * @param {number} x1 - 第一个点的x坐标
 * @param {number} x2 - 第二个点的x坐标
 * @param {number} y1 - 第一个点的y坐标
 * @param {number} y2 - 第二个点的y坐标
 * @param {number} ad - y坐标差（y2 - y1）
 * @param {number} ab - x坐标差（x2 - x1）
 * @returns {number} 返回计算得到的角度值
 */
function countAngle2(x1, x2, y1, y2, ad, ab) {
  // 计算两点之间的角度
  let angle = Math.abs((Math.atan(ad / ab) * 180) / Math.PI);

  // 根据点的位置调整角度
  if (x2 > x1 && y2 < y1) {
    // 第二点在第一点的右下方
    angle = 180 - angle;
  }

  if (x2 < x1 && y2 < y1) {
    // 第二点在第一点的左下方
    angle = 180 + angle;
  }

  if (x2 < x1 && y2 > y1) {
    // 第二点在第一点的左上方
    angle = 360 - angle;
  }

  return angle;
}

/**
 * 将角度转换为特定格式的字符串表示。
 *
 * @param angle 数字类型，表示角度值。
 * @param flag 布尔类型，如果为true，则角度值保留两位小数；如果为false，则不保留小数。
 * @returns {string} 返回字符串，格式为"N角度°E"，其中角度根据flag的值可能保留两位小数。
 */
function small90(angle, flag) {
  // 判断flag的值
  if (flag) {
    // 如果flag为true，则角度值保留两位小数，并返回格式化的字符串
    return `N${angle.toFixed(2)}°E`;
  } else {
    // 如果flag为false，则不保留小数，并返回格式化的字符串
    return `N${angle}°E`;
  }
}

/**
 * 根据角度值获取水平方位角表示
 *
 * @param {number} angle - 角度值，单位为度
 * @param {boolean} flag - 标记参数，默认为false
 * @returns {string} - 水平方位角的字符串表示
 */
export function getHoriAzimuthAngle(angle, flag = false) {
  // 如果角度值小于0或未定义或为null或为空字符串，则返回空字符串
  if (angle < 0 || angle === undefined || angle === null || angle === "") {
    return "";
  }

  // 如果角度值为0，则返回"N"
  if (angle == 0) {
    return "N";
  }

  // 如果角度值大于0且小于90，调用small90函数处理
  else if (angle > 0 && angle < 90) {
    return small90(angle, flag);
  }

  // 如果角度值等于90，则返回"90°E"
  else if (angle === 90) {
    return "90°E";
  }

  // 如果角度值大于90且小于180，返回格式化的字符串
  else if (angle > 90 && angle < 180) {
    return `S${(180 - angle).toFixed(2)}°E`;
  }

  // 如果角度值等于180，则返回"S180°"
  else if (angle === 180) {
    return "S180°";
  }

  // 如果角度值大于180且小于270，返回格式化的字符串
  else if (angle > 180 && angle < 270) {
    return `S${(angle - 180).toFixed(2)}°W`;
  }

  // 如果角度值等于270，则返回"270°W"
  else if (angle === 270) {
    return "270°W";
  }

  // 如果角度值大于270，返回格式化的字符串
  else {
    return `N${(360 - angle).toFixed(2)}°W`;
  }
}
